package cz.acies.uniql.sql.element;

import java.sql.Types;
import java.util.*;

import org.dom4j.Element;
import org.dom4j.dom.DOMElement;


import cz.acies.uniql.dialect.Dialect;
import cz.acies.uniql.dialect.MSSQLDialect;
import cz.acies.uniql.dialect.MySQLDialect;
import cz.acies.uniql.dialect.OracleDialect;
import cz.acies.uniql.dialect.PostgreDialect;
import cz.acies.uniql.metadata.DBMetaData;
import cz.acies.uniql.metadata.FieldMetaData;
import cz.acies.uniql.metadata.TableMetaData;
import cz.acies.uniql.sql.UniQLExpr;
import cz.acies.uniql.sql.functions.SQLFunc;
import cz.acies.uniql.sql.functions.UniQLBracketExpr;
import cz.acies.uniql.utils.UniQLConfig;

/**
 * The Class UniQLCondition.
 */
public class UniQLCondition extends UniQLExpr
{
	private static final long serialVersionUID = -1588327867494176195L;
	
	public static final int EQUALS = 0;
	public static final int NOT_EQUALS = 1;
	public static final int GREATER = 2;
	public static final int LOWER = 3;
	public static final int GREATER_EQUALS = 4;
	public static final int LOWER_EQUALS = 5;
	public static final int LIKE = 6;
	public static final int NOT_LIKE = 7;
	public static final int IN = 8;
	public static final int NOT_IN = 9;
	public static final int BETWEEN = 10;
	public static final int NOT_BETWEEN = 11;
	public static final int IS_NULL = 12;
	public static final int NOT_IS_NULL = 13;
	public static final int REGEXP = 14;
	public static final int NOT_REGEXP = 15;
	
	private int op = -1;
	private UniQLExpr expr1, expr2;
	
	private static Hashtable<String, Integer> operators = new Hashtable<String, Integer>();
	static {
		operators.put("=", new Integer(EQUALS));
		operators.put("<>", new Integer(NOT_EQUALS));
		operators.put("!=", new Integer(NOT_EQUALS));
		operators.put("<", new Integer(GREATER));
		operators.put(">", new Integer(LOWER)); 
		operators.put("<=", new Integer(GREATER_EQUALS));
		operators.put(">=", new Integer(LOWER_EQUALS));
		operators.put("LIKE", new Integer(LIKE));
		operators.put("NOT LIKE", new Integer(NOT_LIKE));
		operators.put("IN", new Integer(IN));
		operators.put("NOT IN", new Integer(NOT_IN));
		operators.put("BETWEEN", new Integer(BETWEEN));
		operators.put("NOT BETWEEN", new Integer(NOT_BETWEEN));
		operators.put("IS NULL", new Integer(IS_NULL));
		operators.put("NOT IS NULL", new Integer(NOT_IS_NULL));
		
		operators.put("REGEXP", new Integer(REGEXP));
		operators.put("NOT REGEXP", new Integer(NOT_REGEXP));
	}


	/**
	 * Konstruktor tridy UniQLCondition.
	 */
	public UniQLCondition() {
	}
	
	/**
	 * Konstruktor tridy UniQLCondition.
	 * 
	 * @param dialect - dialect
	 */
	public UniQLCondition(Dialect dialect) {
		super(dialect);
	}
	
	/**
	 * Konstruktor tridy UniQLCondition.
	 * 
	 * @param expr1 - expr1
	 * @param operator - operator
	 * @param expr2 - expr2
	 */
	public UniQLCondition(Object expr1, String operator, Object expr2) {
		super();
		setOperator(operator);
		setLeftFragment(expr1);		
		setRightFragment(expr2);
	}

	/**
 	 * Konstruktor tridy UniQLCondition s jedn�m parametrem typu UniQLExpr pro 
 	 * vytvo�en� podm�nky typu ISNULL, NOT ISNULL apod.
	 *   
	 * @param expr1 - expr1
	 */
	public UniQLCondition(Object expr1) {
		super();
		setLeftFragment(expr1);
	}

	/**
	 * Konstruktor vytvori nonou instanci objektu UniQLCondition s vlastnostmi
	 * objektu zadaneho jako parametr konstruktoru.
	 *  
	 * @param orderBy
	 */
	public UniQLCondition(UniQLCondition expr) throws Exception {
		this();
		UniQLCondition clone = (UniQLCondition) expr.clone();
		
		setId(clone.getId());
		setName(clone.getName());
		setDialect(clone.getDialect());
		setAliasMap(clone.getAliasMap());

		setOperator(clone.getOperator());
		setLeftFragment((clone.getLeftFragment() != null) ? clone.getLeftFragment() : null);
		setRightFragment((clone.getRightFragment() != null) ? clone.getRightFragment() : null);
	}
	
	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#translate()
	 */
	public String translate() throws Exception {
		//System.out.println("UniQLCondition.translate(0)");
		StringBuffer sb = new StringBuffer();
		Dialect dialect = this.getDialect();
		
		switch (this.op) {
			case BETWEEN:
			case NOT_BETWEEN: {
				if (getLeftFragment() != null && getRightFragment() != null) {
					UniQLExpr expr = transferFieldConvert(getLeftFragment(), true);
					expr.setUniQLProperties(this);
					sb.append(expr.translate()+" ");
					sb.append(getOperatorString().trim()+" ");
					expr = getRightFragment();
					if (expr instanceof UniQLBracketExpr) {
						String s = expr.translate();
						if (s.length() > 2) {
							s = s.substring(1, s.length() -1);
						}
						sb.append(s + "");
					} else if (expr instanceof UniQLConditionBetweenParams) {
						String s = expr.translate();
						sb.append(s + "");
					}
				}
				break;
			}
			case REGEXP:
			case NOT_REGEXP: {
				if (dialect instanceof OracleDialect) {
					if (getLeftFragment() != null && getRightFragment() != null) {
						sb.append(((this.op == NOT_REGEXP) ? "NOT " : "") + "REGEXP_LIKE(");
						UniQLExpr expr = transferFieldConvert(getLeftFragment(), true);
						expr.setUniQLProperties(this);
						sb.append(expr.translate()+", ");
						expr = getRightFragment();
						expr.setUniQLProperties(this);
						sb.append(expr.translate()+" ");						
						sb.append(") ");
					}
					//NOT regexp_like(tbl0."EMAIL", '^[_a-zA-Z0-9\.\-]+@[_a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,4}$')
				} else if (dialect instanceof PostgreDialect) {
					if (getLeftFragment() != null && getRightFragment() != null) {
						UniQLExpr expr = transferFieldConvert(getLeftFragment(), true);
						expr.setUniQLProperties(this);
						sb.append(expr.translate()+" ");
						sb.append(((this.op == NOT_REGEXP) ? "!" : "") + "~ ");
						expr = transferFieldConvert(getRightFragment(), true);
						expr.setUniQLProperties(this);
						sb.append(expr.translate()+" ");
					}					
					//telephone."NUMBER" ~ '^[_a-zA-Z0-9\.\-]+@[_a-zA-Z0-9\.\-]+\.[a-zA-Z]{2,4}$'
				} else {
					sb = standardTranslate();
				}
				break;
			}
			default: {
				sb = standardTranslate();
				break;
			}
		}
		return sb.toString();
	}

	private StringBuffer standardTranslate()  throws Exception {
		StringBuffer sb = new StringBuffer();
		Dialect dialect = this.getDialect();
		HashMap<String, Object> aliasMap = this.getAliasMap();

		if (getLeftFragment() != null) {
			UniQLExpr expr = null;
			if (getOperatorString() != null && (getOperatorString().trim().equals("LIKE") || getOperatorString().trim().equals("="))) {
				if (dialect instanceof PostgreDialect) {
					if (getOperatorString().trim().equals("LIKE")) {
						expr = getLeftFragment();
						FieldMetaData fmd = null;
						if (expr instanceof UniQLColumn) fmd = searchMetaDataForColumn((UniQLColumn)expr);
						if (fmd != null) {
							int sqltype = fmd.getSqlType();
							switch (sqltype) {
								case Types.INTEGER: {
									UniQLExpr newExpr = new SQLFunc("to_varchar")
									.addParam((UniQLExpr)expr)
									.addParam(new UniQLValue("'99999999999'"));
									expr = new SQLFunc("trim").addParam(newExpr);	
									expr.setDialect(dialect);
									expr.setAliasMap(aliasMap);
									sb.append(expr.translate()+" ");
									break;
								}
								default: {
									expr = transferFieldConvert(getLeftFragment(), true);
									expr.setDialect(dialect);
									expr.setAliasMap(aliasMap);
									sb.append(expr.translate()+" ");									
									break;
								}
							}
						} else {
							//expr = transferFieldConvert(getLeftFragment(), true);
							expr = transferFieldConvert(getLeftFragment(), true);
							expr.setDialect(dialect);
							expr.setAliasMap(aliasMap);
							sb.append(expr.translate()+" ");
						}
					} else {
						expr = transferFieldConvert(getLeftFragment(), true);
						expr.setDialect(dialect);
						expr.setAliasMap(aliasMap);
						sb.append(expr.translate()+" ");						
					}
				} else {					
					expr = transferFieldConvert(getLeftFragment(), true);
					//expr.setDialect(dialect);
					//expr.setAliasMap(aliasMap);
					expr.setUniQLProperties(this);
					sb.append(expr.translate()+" ");	
				}
			} else {
				expr = transferFieldConvert(getLeftFragment(), true);
				expr.setDialect(dialect);
				expr.setAliasMap(aliasMap);
				sb.append(expr.translate()+" ");
			}
			if (getOperatorString() != null) {
				if (getOperatorString().trim().equals("LIKE")) {
					sb.append(getOperatorString().trim()+" ");
					expr = transferFieldConvert(getRightFragment(), false);
					expr.setDialect(dialect);
					expr.setAliasMap(aliasMap);
					sb.append(expr.translate()+" ");	
				} else {
					sb.append(getOperatorString().trim()+" ");
					expr = transferFieldConvert(getRightFragment(), false);
					expr.setDialect(dialect);
					expr.setAliasMap(aliasMap);
					sb.append(expr.translate()+" ");
				}
			}
		}		
		return sb;
	}
	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#clear()
	 */
	public UniQLExpr clear() {
		op = -1;
		expr1.clear(); expr1 = null;
		expr2.clear(); expr2 = null;
		return this;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	@Override
	public Object clone() throws CloneNotSupportedException {
		Object clone = super.clone();
		assert clone instanceof UniQLCondition;
		((UniQLCondition) clone).setOperator(getOperator());
		((UniQLCondition) clone).setLeftFragment((getLeftFragment() != null) ? (UniQLExpr)getLeftFragment().clone() : null);
		((UniQLCondition) clone).setRightFragment((getRightFragment() != null) ? (UniQLExpr)getRightFragment().clone() : null);
		return clone;
	}

	
	// -----  -----------------------------------------------------------------
	/*
	public int getFieldType(UniQLExpr expr) {
		try {
			HashMap<String, Object> aliasMap = this.getAliasMap();	
			if (expr instanceof UniQLColumn) {
				TableMetaData tbmd = null;
				String name = expr.getName();
				String tableName = ((UniQLColumn)expr).getTableName();
				if (tableName != null ) {
					tableName = tableName.toLowerCase();
					if (getAliasMap().containsKey(tableName)) {
						tableName = (String)getAliasMap().get(tableName);
						tableName = tableName.toLowerCase();							
					}
				} else {
					HashMap<String, Object> fromIndex = (HashMap<String, Object>)aliasMap.get("fromIndex");
					Object[] keys = fromIndex.keySet().toArray();
					for (int i = 0; i < keys.length; i++) {
						String key = (String)keys[i];
						if (fromIndex.get(key) instanceof UniQLFrom) {
							UniQLFrom from = (UniQLFrom)fromIndex.get(key);
							tableName = from.getName();
							if (tableName != null) {
								tableName = tableName.toLowerCase();
								tbmd = getDialect().dbmd().getTable(tableName);
								if (tbmd != null) {
									if (tbmd.getColNameIndex().containsKey(name)) {
										break;
									} else {
										tbmd = null;
										tableName = null;											
									}
								}
							}
						}
					}
				}
				if (tableName != null) {
					tbmd = getDialect().dbmd().getTable(tableName);
				}
				if (tbmd != null) {
					FieldMetaData fmd = tbmd.getFieldByName(name);
					if (fmd != null) {
						return fmd.getSqlType();
					}
				}
			}
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return 9999;
	}
	*/
	/**
	 * 
	 * @param expr
	 * @param isLeft
	 * @return
	 */
	private UniQLExpr transferFieldConvert(UniQLExpr expr, boolean isLeft) {
		try {
			HashMap<String, Object> aliasMap = this.getAliasMap();
			Dialect dialect = this.getDialect();			
			if (aliasMap != null && !(dialect instanceof MySQLDialect)) {
				if (expr instanceof UniQLColumn) {
					FieldMetaData fmd = searchMetaDataForColumn((UniQLColumn)expr);
					if (fmd != null) {
						int sqltype = fmd.getSqlType();
						switch (sqltype) {
							case Types.LONGVARCHAR:
							case Types.CLOB: {
								UniQLExpr newExpr = new SQLFunc("text_to_varchar").addParam(expr);
								newExpr.setDialect(getDialect());
								expr = newExpr;
								break;
							}
							case Types.TIMESTAMP: 
							case Types.DATE: {
								Object expr2 = null;
								if (dialect instanceof MSSQLDialect) {
									if (expr instanceof UniQLColumn) {
										UniQLExpr newExpr = new SQLFunc("date_to_varchar").addParam((UniQLExpr)expr);
										newExpr.setDialect(getDialect());
										if (isLeft) {
											this.setLeftFragment(newExpr);
										} else {
											this.setRightFragment(newExpr);
										}
										expr = newExpr;
									}
								} else {
									if (isLeft) {
										expr2 = this.getRightFragment();
									} else {
										expr2 = this.getLeftFragment();
									}
									if (expr2 != null && expr2 instanceof UniQLValue) {
										UniQLExpr newExpr = new SQLFunc("to_timestamp").addParam((UniQLExpr)expr2);
										newExpr.setDialect(getDialect());
										if (isLeft) {
											this.setRightFragment(newExpr);
										} else {
											this.setLeftFragment(newExpr);
										}										
									}
								}
								break;									
							}
							case Types.INTEGER: {
								break;
							}
							default: {
								break;
							}
						}
					}
				}
			} else if (UniQLConfig.DEBUG_MODE) {
				if (aliasMap != null) {
					if (expr instanceof UniQLColumn) {
						TableMetaData tbmd = null;
						String name = expr.getName();
						String tableName = ((UniQLColumn)expr).getTableName();
						if (tableName != null ) {
							tableName = tableName.toLowerCase();
							if (getAliasMap().containsKey(tableName)) {
								tableName = (String)getAliasMap().get(tableName);
								tableName = tableName.toLowerCase();							
							}
						} else {
							HashMap<String, Object> fromIndex = (HashMap<String, Object>)aliasMap.get("fromIndex");
							Object[] keys = fromIndex.keySet().toArray();
							for (int i = 0; i < keys.length; i++) {
								String key = (String)keys[i];
								if (fromIndex.get(key) instanceof UniQLFrom) {
									UniQLFrom from = (UniQLFrom)fromIndex.get(key);
									tableName = from.getName();
									if (tableName != null) {
										tableName = tableName.toLowerCase();
										tbmd = dbmd().getTable(tableName);
										if (tbmd != null) {
											if (tbmd.getColNameIndex().containsKey(name)) {
												break;
											} else {
												tbmd = null;
												tableName = null;											
											}
										}
									}
								}
							}
							if (tableName != null) {
								tbmd = dbmd().getTable(tableName);
							}
							if (tbmd != null) {
								FieldMetaData fmd = tbmd.getFieldByName(name);
								if (fmd != null) {
									int sqltype = fmd.getSqlType();
									switch (sqltype) {
										case Types.LONGVARCHAR:
										case Types.CLOB: {
											throw new Exception(
												"ERORR cz.acies.uniql.sql.element.UniQLCondition: \n\t" +
												"column(" + fmd.getName() + ").sqltype is LONGVARCHAR or CLOB,\n\t" +
												"but is not convert to varchar..."
											);
											//break;
										}
										case Types.TIMESTAMP: 
										case Types.DATE: {
											break;									
										}
										case Types.INTEGER: {
											break;
										}
										default: {
											break;
										}
									}
								}
							}
						}
					}
				}
			}
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return expr;
	}
	
	// -----  -----------------------------------------------------------------
	
	private FieldMetaData searchMetaDataForColumn(UniQLColumn expr) {
		TableMetaData tbmd = searchTableForColumn(expr);
		if (tbmd == null) return null;
		String name = expr.getName();
		String table = expr.getTableName(); 
		return  searchMetaDataForColumn(name, tbmd);
	}
	
	private FieldMetaData searchMetaDataForColumn(String name, TableMetaData tbmd) {		
		FieldMetaData fmd = null;
		try {
			if (tbmd == null) return null;
			fmd = tbmd.getFieldByName(name);
		} catch (Exception exc) {
			exc.printStackTrace();
			return null;
		}
		return fmd;
	}
	
	private TableMetaData searchTableForColumn(UniQLColumn expr) {
		if (!(expr instanceof UniQLColumn)) return null;
		HashMap<String, Object> aliasMap = this.getAliasMap();
		TableMetaData tbmd = null;
		String name = expr.getName();
		String tableName = ((UniQLColumn)expr).getTableName();
		if (tableName != null ) {
			tableName = tableName.toLowerCase();
			if (aliasMap.containsKey(tableName)) {
				tableName = (String)getAliasMap().get(tableName);
				tableName = tableName.toLowerCase();							
			}
		} else {
			HashMap<String, Object> fromIndex = (HashMap<String, Object>)aliasMap.get("fromIndex");
			Object[] keys = fromIndex.keySet().toArray();
			for (int i = 0; i < keys.length; i++) {
				String key = (String)keys[i];
				if (fromIndex.get(key) instanceof UniQLFrom) {
					UniQLFrom from = (UniQLFrom)fromIndex.get(key);
					tableName = from.getName();
					if (tableName != null) {
						tableName = tableName.toLowerCase();
						tbmd = dbmd().getTable(tableName);
						if (tbmd != null) {
							if (tbmd.getColNameIndex().containsKey(name)) {
								break;
							} else {
								tbmd = null;
								tableName = null;											
							}
						}
					}
				}
			}
		}
		if (tableName != null) {
			tbmd = dbmd().getTable(tableName);
		}
		return tbmd;
	}
	
	// -----  -----------------------------------------------------------------

	/**
	 * Zada ciselnou hodnotu operatoru. Ciselna hodnota je prezentovana 
	 * konstantou. (napr. EQUALS). 
	 * 
	 * @param op nova hodnota promenne operator
	 */
	public void setOperator(int op) {
		this.op = op;
	}

	/**
	 * Zada stringovou hodnotu operatoru. 
	 * 
	 * @param key - nova hodnota operator (napr. "=")
	 */
	public void setOperator(String key) {
		if (key != null) {
			if (operators.containsKey(key.trim())) this.op = ((Integer)operators.get(key)).intValue();
		}
	}

	/**
	 * Navraci ciselnou hodnotu operatoru.
	 * 
	 * @return - vraci hodnotu operator
	 */
	public int getOperator() {
		return this.op;
	}

	/**
	 * Navraci stringovou hodnotu operatoru.
	 * 
	 * @return - vraci stringovou hodnotu operatoru 
	 */
	public String getOperatorString() {
		String s = new String();
		if (getOperator() == -1) return null;
		int i = new ArrayList<Integer>(operators.values()).indexOf(op);
		s = new ArrayList<String>(operators.keySet()).get(i);
		if (s == null) s = "";
		return s;
	}

	// -----  -----------------------------------------------------------------

	/**
	 * Zada hodnotu prvniho fragmentu.
	 * 
	 * @param expr - nova hodnota left fragment.Parametr muze byt objekt typu
	 * String nebo UniQLExpr.
	 */
	public void setLeftFragment(Object expr) { 
		if (expr instanceof String) {
			this.expr1 = new UniQLColumn((String)expr);
		} else if (expr instanceof UniQLExpr) {
			this.expr1 = (UniQLExpr)expr;
		}
	}

	/**
	 * Zada hodnotu leveho fragmentu.
	 * 
	 * @param expr - nova hodnota leveho fragment. Parametr muze byt objekt typu
	 * UniQLExpr.
	 */
	public void setLeftFragment(UniQLExpr expr) {
		this.expr1 = expr;
	}

	/**
	 * Navraci hodnotu leveho fragmentu.
	 * 
	 * @return Vraci hodnotu leveho fragmentu. Hodnota je objekt typu UniQLExpr
	 */
	public UniQLExpr getLeftFragment() {
		return this.expr1;
	}

	/**
	 * Zada hodnotu praveho fragmentu.
	 * 
	 * @param expr nova hodnota praveho fragmentu. Parametr muze byt objekt typu
	 * String nebo UniQLExpr.
	 */
	public void setRightFragment(Object expr) { 
		if (expr instanceof String) {
			String s = ((String)expr).trim();
			if (s.startsWith("'") ) {
				UniQLValue value = new UniQLValue();
				value.set(s);
				this.expr2 = value; 
			} else {
				this.expr2 = new UniQLColumn((String)expr);
			}
		} else if (expr instanceof UniQLExpr) {
			this.expr2 = (UniQLExpr)expr;
		}
	}
	
	/**
	 * Zada hodnotu praveho fragmentu.
	 * 
	 * @param expr nova hodnota praveho fragmentu.Parametr muze byt objekt typu
	 * UniQLExpr.
	 */
	public void setRightFragment(UniQLExpr expr) {
		this.expr2 = expr;
	}
	
	/**
	 * Navraci hodnotu praveho fragmentu.
	 * 
	 * @return - vraci hodnotu praveho fragmentu
	 */
	public UniQLExpr getRightFragment() {
		return this.expr2;
	}

	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#setDialect(cz.acies.uniql.dialect.Dialect)
	 */
	public void setDialect(Dialect dialect) {
		super.setDialect(dialect);
		if (expr1 != null) expr1.setDialect(this.getDialect());
		if (expr2 != null) expr2.setDialect(this.getDialect());
	}

	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#transToXML()
	 */
	public String transToXML() throws Exception {
		DOMElement node = new DOMElement("UniQLCondition");
		transToXML(node);
		return node.asXML();
	}
	
	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#transToXML(org.dom4j.dom.DOMElement)
	 */
	public DOMElement transToXML(DOMElement node) throws Exception {
		//String columnName = this.getName();
		node.setName("UniQLCondition");
		if (getLeftFragment() != null) {
			DOMElement expr1 = getLeftFragment().transToXML(new DOMElement("UniQLExpr"));
			node.appendChild(expr1);
			if (getOperatorString() != null) {
				DOMElement operand = new DOMElement("operator");
				operand.setAttribute("value", getOperatorString().trim());
				node.appendChild(operand);
				DOMElement expr2 = getRightFragment().transToXML(new DOMElement("UniQLExpr"));
				node.appendChild(expr2);
			}
		}
		return node;
	}

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#xmlToExpr(java.lang.String)
	 */
	public UniQLExpr xmlToExpr(String xml) throws Exception {
		return this;
	}

	/* (non-Javadoc)
	 * @see cz.acies.uniql.sql.UniQLExpr#xmlToExpr(org.dom4j.Element)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public UniQLExpr xmlToExpr(Element node) throws Exception {
		ArrayList params = new ArrayList(node.elements());
		//System.out.println("UniQLCondition.xmlToExpr().params = " + params);
		for (int i = 0; i < params.size(); i++) {
			Element param = (Element)params.get(i);
			//System.out.println("\tUniQLCondition.xmlToExpr("+i+").param = " + param.asXML());
			String nodename = param.getName();
			//System.out.println("\tUniQLCondition.xmlToExpr("+i+").nodename = " + nodename);
			UniQLExpr expr = null; 
			if (nodename.trim().equals("UniQLColumn")) {
				expr = new UniQLColumn(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("UniQLValue")) {
				expr = new UniQLValue(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("SQLFunc")) {
				expr = new SQLFunc(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("UniQLConditionGroup")) {
				expr = new UniQLConditionGroup(getDialect()).xmlToExpr(param);								
			} else if (nodename.trim().equals("UniQLFullText")) {
				expr = new UniQLFullText(getDialect()).xmlToExpr(param);
			} else if (nodename.trim().equals("UniQLCriterion")) {
				expr = new UniQLCriterion(getDialect()).xmlToExpr(param);
			}
			switch (i) {
				case 0: { setLeftFragment(expr); 	break; }
				case 2: { setRightFragment(expr); 	break; }
				default: break;
			}
			if (nodename.equals("operator")) {
				String key = param.attributeValue("value");
				this.setOperator(key);
			}
		}
		//System.out.println("UniQLCondition.xmlToExpr() >>> "+this.toString());
		return this;
	}
	
	// -----  -----------------------------------------------------------------
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return "UniQLCondition( "+this.getLeftFragment()+" "+this.getOperatorString()+" "+this.getRightFragment()+" )";
	}
}
